package com.jt.config;

import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.*;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import java.util.Arrays;
@AllArgsConstructor
@Configuration
@EnableAuthorizationServer
public class Oauth2Config extends AuthorizationServerConfigurerAdapter {

    private TokenStore tokenStore;
    private AuthenticationManager authenticationManager;
    private UserDetailsService userDetailsService;
    private JwtAccessTokenConverter jwtAccessTokenConverter;
    private PasswordEncoder passwordEncoder;

    @Override//配置认证规则
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//        super.configure(endpoints);
        endpoints.authenticationManager(authenticationManager)//配置由谁完成认证
                .userDetailsService(userDetailsService)//配置由谁负责查询用户业务数据
                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)//配置可以处理的认证请求方式
                .tokenServices(tokenServices());//配置token生成及存储策略（默认是UUID随机的字符串）
    }
    @Bean
    public AuthorizationServerTokenServices tokenServices(){
        DefaultTokenServices tokenServices = new DefaultTokenServices();//使用他的默认实现类
        tokenServices.setTokenStore(tokenStore);//配置令牌的创建和存储对象(tokenStore)
        //配置令牌增强（默认是uuid）
        TokenEnhancerChain tokenEnhancer = new TokenEnhancerChain();
        tokenEnhancer.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter));

        tokenServices.setTokenEnhancer(tokenEnhancer);
        tokenServices.setAccessTokenValiditySeconds(3600);//设置令牌时常1小时
        tokenServices.setSupportRefreshToken(true);//设置是否刷新令牌
        tokenServices.setRefreshTokenValiditySeconds(3600*5);//设置刷新令牌有效时长5小时
        return tokenServices;
    }
    //配置对谁颁发令牌，客户端需要有什么特点
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//        super.configure(clients);
        clients.inMemory()
                //定义客户端需要携带的id
                .withClient("gateway-client")
                //定义客户端需要携带的密钥
                .secret(passwordEncoder.encode("123456"))
                //定义作用范围（所有符合定义规则的客户端）
                .scopes("all")
                //定义允许的认证方式（可以基于密码进行认证，也可以基于刷新令牌进行认证）
                .authorizedGrantTypes("password","refresh_token");
    }
    //配置对外暴露的认证url，刷新令牌的url，检查令牌的url等
    //我们登陆时要对哪个url发起请求，通过哪个url可以解析令牌
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
//        super.configure(security);
      security.tokenKeyAccess("permitAll()")//公开认证的url
                .checkTokenAccess("permitAll")//公开检查token有效性的url
                .allowFormAuthenticationForClients();//允许通过表单提交的方式进行认证
    }
}
